Biphenyl DFTB Torsional PES Scan¶
This report shows a scan of the central torsion in biphenyl with DFTB and summarizes the resulting energy profile, representative structures, and reusable Python workflow.
DFTB torsional potential-energy profile of biphenyl.¶
Requires: AMS2026 or later
Related documentation
Setup¶
Biphenyl was built from SMILES c1ccccc1-c2ccccc2 with ChemicalSystem.from_smiles. The central inter-ring C-C bond was identified by inspecting ChemicalSystem.bonds for the carbon-carbon bond whose removal cuts the molecule.
Central inter-ring bond, zero-based atom indices:
(5, 6)Central inter-ring bond, AMS one-based atom indices:
(6, 7)Inter-ring dihedral, zero-based atom indices:
(0, 5, 6, 7)Inter-ring dihedral, AMS one-based atom indices:
(1, 6, 7, 8)
The constrained AMS PESScan used DFTB with Model GFN1-xTB, scanning the inter-ring dihedral from 0 to 180 degrees in 19 points, i.e. 10 degree spacing. Energies below are reported relative to the lowest scan point.
Results¶
Minimum-energy scan point: 140.0 degrees.
Minimum-energy biphenyl twist angle: 40.0 degrees. This is reported as min(dihedral, 180 - dihedral) because the 0 to 180 degree scan has equivalent twisted structures on either side of 90 degrees.
Torsional barrier to the planar structure: 1.8050 kcal/mol. The 0 and 180 degree planar endpoints are both tabulated below; the quoted planar barrier is the lower of the two endpoint relative energies.
Torsional barrier to the perpendicular structure: 1.7045 kcal/mol.
Representative optimized structures¶
Planar geometry:
Minimum-energy geometry:
Perpendicular geometry:
Scan table¶
Dihedral angle (deg) |
Absolute energy (Hartree) |
Relative energy (kcal/mol) |
|---|---|---|
0.0 |
-30.7270479157 |
1.8050 |
10.0 |
-30.7276375568 |
1.4350 |
20.0 |
-30.7287351168 |
0.7463 |
30.0 |
-30.7296159661 |
0.1936 |
40.0 |
-30.7299151698 |
0.0058 |
50.0 |
-30.7296468314 |
0.1742 |
60.0 |
-30.7289488005 |
0.6122 |
70.0 |
-30.7281162675 |
1.1346 |
80.0 |
-30.7274575254 |
1.5480 |
90.0 |
-30.7272081545 |
1.7045 |
100.0 |
-30.7274586820 |
1.5473 |
110.0 |
-30.7281246087 |
1.1294 |
120.0 |
-30.7289611334 |
0.6045 |
130.0 |
-30.7296515698 |
0.1712 |
140.0 |
-30.7299244088 |
0.0000 |
150.0 |
-30.7296195325 |
0.1913 |
160.0 |
-30.7287447482 |
0.7402 |
170.0 |
-30.7276400215 |
1.4335 |
180.0 |
-30.7270454035 |
1.8066 |
AMS input¶
The PES scan job was loaded from /home/ubuntu/work/01-run-biphenyl-dftb-pesscan_workdir/biphenyl_dftb_torsion with AMSJob.load_external(...).
PESScan
Optimize True
ScanCoordinate
Dihedral 1 6 7 8 0.0 180.0
nPoints 19
End
End
Task PESScan
System
Atoms
C 1.5436277587 -0.6712511736 -0.8743423895
C 2.9379238219 -0.6084386430 -0.7895740467
C 3.5458648903 0.1540229069 0.2101358580
C 2.7607157299 0.8559722841 1.1272880062
C 1.3659731986 0.7976348543 1.0467720204
C 0.7407365542 0.0321748032 0.0438974615
C -0.7407365262 -0.0321759898 -0.0438985615
C -1.3882544717 -1.2464975341 -0.3418076249
C -2.7829651518 -1.3041919267 -0.4233311075
C -3.5458647518 -0.1540214568 -0.2101369285
C -2.9156742946 1.0566598609 0.0856160895
C -1.5213463694 1.1201124254 0.1693765138
H 1.0941322198 -1.2547297485 -1.6679429353
H 3.5475041862 -1.1489839049 -1.5021581640
H 4.6253028921 0.2009111764 0.2741061689
H 3.2330362523 1.4435115455 1.9039896331
H 0.7773312479 1.3360188999 1.7788506547
H -0.8179456227 -2.1542017782 -0.4938473594
H -3.2727104357 -2.2427544850 -0.6487281126
H -4.6253028983 -0.2009093371 -0.2741044826
H -3.5078300382 1.9482274962 0.2468998516
H -1.0535181915 2.0729097247 0.3829394549
End
BondOrders
1 2 1.5
1 6 1.5
1 13 1.0
2 3 1.5
2 14 1.0
3 4 1.5
3 15 1.0
4 5 1.5
4 16 1.0
5 6 1.5
5 17 1.0
6 7 1.0
7 8 1.5
7 12 1.5
8 9 1.5
8 18 1.0
9 10 1.5
9 19 1.0
10 11 1.5
10 20 1.0
11 12 1.5
11 21 1.0
12 22 1.0
End
End
Engine dftb
Model GFN1-xTB
EndEngine
Conclusion¶
The DFTB scan places the minimum at a scan dihedral of 140.0 degrees, corresponding to a biphenyl twist of 40.0 degrees. Relative to this point, the lower planar endpoint is 1.8050 kcal/mol higher and the perpendicular point is 1.7045 kcal/mol higher.
Prompts and Python scripts¶
Prompt (instruction for AI agent)
Use $ams2026
Calculate the torsional potential energy profile of biphenyl with DFTB.
Build biphenyl from SMILES c1ccccc1-c2ccccc2. Identify the central inter-ring
C-C bond and the four atoms defining the inter-ring dihedral by inspecting
the ChemicalSystem bonds.
Run a constrained AMS PES Scan over the inter-ring dihedral from 0 to 180
degrees in 10 degree steps. Use DFTB.
Plot relative energy in kcal/mol vs dihedral angle. In the report, identify
the minimum-energy twist angle and the torsional barriers to the planar and
perpendicular structures.
Include pictures of the optimized structures at the planar geometry, the
minimum-energy geometry, and the perpendicular geometry. Include a table
with dihedral angle, absolute energy, and relative energy for all scan points.
01-run-biphenyl-dftb-pesscan.py
#!/usr/bin/env amspython
from __future__ import annotations
from dataclasses import dataclass
from scm.base import ChemicalSystem
from scm.input_classes import AMS
from scm.plams import AMSJob, Settings, init
SMILES = "c1ccccc1-c2ccccc2"
JOB_NAME = "biphenyl_dftb_torsion"
@dataclass(frozen=True)
class TorsionDefinition:
central_bond: tuple[int, int]
dihedral: tuple[int, int, int, int]
@property
def ams_dihedral_line(self) -> str:
a, b, c, d = (idx + 1 for idx in self.dihedral)
return f"{a} {b} {c} {d} 0.0 180.0"
def carbon_neighbors(system: ChemicalSystem, atom_index: int, exclude: int) -> list[int]:
return [
idx
for idx in system.bonds.get_bonded_atoms(atom_index)
if idx != exclude and system.atoms[idx].symbol == "C"
]
def identify_inter_ring_torsion(system: ChemicalSystem) -> TorsionDefinition:
candidates: list[tuple[int, int]] = []
for i, j, _bond in system.bonds:
if system.atoms[i].symbol != "C" or system.atoms[j].symbol != "C":
continue
if system.bond_cuts_molecule(i, j):
candidates.append((i, j))
if len(candidates) != 1:
raise RuntimeError(f"Expected one central inter-ring C-C bond, found {candidates}")
left, right = candidates[0]
left_neighbors = carbon_neighbors(system, left, exclude=right)
right_neighbors = carbon_neighbors(system, right, exclude=left)
if not left_neighbors or not right_neighbors:
raise RuntimeError("Could not find ring-neighbor carbon atoms for the inter-ring dihedral")
return TorsionDefinition(
central_bond=(left, right),
dihedral=(left_neighbors[0], left, right, right_neighbors[0]),
)
def make_settings(torsion: TorsionDefinition) -> Settings:
settings = Settings()
settings.input.ams.task = "PESScan"
settings.input.ams.pesscan.optimize = True
settings.input.ams.pesscan.scancoordinate.npoints = 19
settings.input.ams.pesscan.scancoordinate.dihedral = torsion.ams_dihedral_line
settings.input.dftb.model = "GFN1-xTB"
AMS.from_settings(settings)
return settings
def main() -> None:
init(folder="01-run-biphenyl-dftb-pesscan_workdir")
system = ChemicalSystem.from_smiles(SMILES)
torsion = identify_inter_ring_torsion(system)
settings = make_settings(torsion)
print(f"Built {system.formula()} from SMILES: {SMILES}")
print(f"Central inter-ring C-C bond, zero-based: {torsion.central_bond}")
print(f"Inter-ring dihedral, zero-based: {torsion.dihedral}")
print(f"AMS dihedral scan line: {torsion.ams_dihedral_line}")
job = AMSJob(molecule=system, settings=settings, name=JOB_NAME)
result = job.run()
if not result.ok():
raise RuntimeError(f"AMS job failed; inspect {job.path}")
if __name__ == "__main__":
main()
02-report.py
#!/usr/bin/env amspython
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
from scm.base import ChemicalSystem, Units
from scm.plams import AMSJob, view
SMILES = "c1ccccc1-c2ccccc2"
JOB_NAME = "biphenyl_dftb_torsion"
@dataclass(frozen=True)
class TorsionDefinition:
central_bond: tuple[int, int]
dihedral: tuple[int, int, int, int]
@property
def central_bond_one_based(self) -> tuple[int, int]:
return tuple(idx + 1 for idx in self.central_bond)
@property
def dihedral_one_based(self) -> tuple[int, int, int, int]:
return tuple(idx + 1 for idx in self.dihedral)
def carbon_neighbors(system: ChemicalSystem, atom_index: int, exclude: int) -> list[int]:
return [
idx
for idx in system.bonds.get_bonded_atoms(atom_index)
if idx != exclude and system.atoms[idx].symbol == "C"
]
def identify_inter_ring_torsion(system: ChemicalSystem) -> TorsionDefinition:
candidates: list[tuple[int, int]] = []
for i, j, _bond in system.bonds:
if system.atoms[i].symbol == "C" and system.atoms[j].symbol == "C":
if system.bond_cuts_molecule(i, j):
candidates.append((i, j))
if len(candidates) != 1:
raise RuntimeError(f"Expected one central inter-ring C-C bond, found {candidates}")
left, right = candidates[0]
left_neighbors = carbon_neighbors(system, left, exclude=right)
right_neighbors = carbon_neighbors(system, right, exclude=left)
if not left_neighbors or not right_neighbors:
raise RuntimeError("Could not find ring-neighbor carbon atoms for the inter-ring dihedral")
return TorsionDefinition(
central_bond=(left, right),
dihedral=(left_neighbors[0], left, right, right_neighbors[0]),
)
def latest_job_path() -> Path:
candidates = sorted(Path(".").glob("01-run-biphenyl-dftb-pesscan_workdir*/" + JOB_NAME))
if not candidates:
raise FileNotFoundError("No biphenyl PES scan job directory was found")
return candidates[-1]
def pesscan_dataframe(job: AMSJob) -> tuple[pd.DataFrame, list[ChemicalSystem]]:
results = job.results.get_pesscan_results()
angles = pd.Series(results["RaveledPESCoords"][0], dtype=float)
if angles.abs().max() <= 2.0 * 3.141592653589793:
angles = angles * Units.conversion_factor("radian", "degree")
energies_hartree = pd.Series(results["PES"], dtype=float)
min_energy_hartree = energies_hartree.min()
relative_kcal = (energies_hartree - min_energy_hartree) * Units.conversion_factor("Hartree", "kcal/mol")
df = pd.DataFrame(
{
"Dihedral angle (deg)": angles.round(6),
"Absolute energy (Hartree)": energies_hartree,
"Relative energy (kcal/mol)": relative_kcal,
}
)
return df, list(results["Molecules"])
def nearest_index(df: pd.DataFrame, target: float) -> int:
return int((df["Dihedral angle (deg)"] - target).abs().idxmin())
def write_plot(df: pd.DataFrame) -> None:
fig, ax = plt.subplots(figsize=(6.5, 4.2))
ax.plot(df["Dihedral angle (deg)"], df["Relative energy (kcal/mol)"], marker="o", linewidth=1.8)
ax.set_xlabel("Dihedral angle (deg)")
ax.set_ylabel("Relative energy (kcal/mol)")
ax.set_xlim(0, 180)
ax.grid(True, alpha=0.25)
fig.tight_layout()
fig.savefig("biphenyl_torsion_profile.png", dpi=180)
plt.close(fig)
def write_structure_images(df: pd.DataFrame, molecules: list[ChemicalSystem]) -> dict[str, str]:
min_idx = int(df["Relative energy (kcal/mol)"].idxmin())
image_specs = {
"planar": nearest_index(df, 0.0),
"minimum": min_idx,
"perpendicular": nearest_index(df, 90.0),
}
output: dict[str, str] = {}
for label, idx in image_specs.items():
filename = f"biphenyl_{label}.png"
view(molecules[idx], width=360, height=280, guess_bonds=True, direction="along_pca3", picture_path=filename)
output[label] = filename
return output
def write_report(job: AMSJob, df: pd.DataFrame, images: dict[str, str], torsion: TorsionDefinition) -> None:
min_idx = int(df["Relative energy (kcal/mol)"].idxmin())
planar0_idx = nearest_index(df, 0.0)
planar180_idx = nearest_index(df, 180.0)
perpendicular_idx = nearest_index(df, 90.0)
min_angle = df.loc[min_idx, "Dihedral angle (deg)"]
min_twist = min(min_angle, 180.0 - min_angle)
planar_barrier = min(
df.loc[planar0_idx, "Relative energy (kcal/mol)"],
df.loc[planar180_idx, "Relative energy (kcal/mol)"],
)
perpendicular_barrier = df.loc[perpendicular_idx, "Relative energy (kcal/mol)"]
table = df.copy()
table["Absolute energy (Hartree)"] = table["Absolute energy (Hartree)"].map(lambda x: f"{x:.10f}")
table["Relative energy (kcal/mol)"] = table["Relative energy (kcal/mol)"].map(lambda x: f"{x:.4f}")
table["Dihedral angle (deg)"] = table["Dihedral angle (deg)"].map(lambda x: f"{x:.1f}")
report = f"""# Biphenyl DFTB torsional PES scan
## Setup
Biphenyl was built from SMILES `{SMILES}` with `ChemicalSystem.from_smiles`. The central inter-ring C-C bond was identified by inspecting `ChemicalSystem.bonds` for the carbon-carbon bond whose removal cuts the molecule.
- Central inter-ring bond, zero-based atom indices: `{torsion.central_bond}`
- Central inter-ring bond, AMS one-based atom indices: `{torsion.central_bond_one_based}`
- Inter-ring dihedral, zero-based atom indices: `{torsion.dihedral}`
- Inter-ring dihedral, AMS one-based atom indices: `{torsion.dihedral_one_based}`
The constrained AMS `PESScan` used DFTB with `Model GFN1-xTB`, scanning the inter-ring dihedral from 0 to 180 degrees in 19 points, i.e. 10 degree spacing. Energies below are reported relative to the lowest scan point.
## Results

Minimum-energy scan point: **{min_angle:.1f} degrees**.
Minimum-energy biphenyl twist angle: **{min_twist:.1f} degrees**. This is reported as `min(dihedral, 180 - dihedral)` because the 0 to 180 degree scan has equivalent twisted structures on either side of 90 degrees.
Torsional barrier to the planar structure: **{planar_barrier:.4f} kcal/mol**. The 0 and 180 degree planar endpoints are both tabulated below; the quoted planar barrier is the lower of the two endpoint relative energies.
Torsional barrier to the perpendicular structure: **{perpendicular_barrier:.4f} kcal/mol**.
## Representative optimized structures
Planar geometry:

Minimum-energy geometry:

Perpendicular geometry:

## Scan table
{table.to_markdown(index=False, disable_numparse=True)}
## AMS input
The PES scan job was loaded from `{job.path}` with `AMSJob.load_external(...)`.
```ams
{job.get_input()}
```
## Conclusion
The DFTB scan places the minimum at a scan dihedral of {min_angle:.1f} degrees, corresponding to a biphenyl twist of {min_twist:.1f} degrees. Relative to this point, the lower planar endpoint is {planar_barrier:.4f} kcal/mol higher and the perpendicular point is {perpendicular_barrier:.4f} kcal/mol higher.
"""
Path("report.md").write_text(report)
def main() -> None:
system = ChemicalSystem.from_smiles(SMILES)
torsion = identify_inter_ring_torsion(system)
job = AMSJob.load_external(str(latest_job_path()))
df, molecules = pesscan_dataframe(job)
write_plot(df)
images = write_structure_images(df, molecules)
write_report(job, df, images, torsion)
if __name__ == "__main__":
main()
Original Markdown report
# Biphenyl DFTB torsional PES scan
## Setup
Biphenyl was built from SMILES `c1ccccc1-c2ccccc2` with `ChemicalSystem.from_smiles`. The central inter-ring C-C bond was identified by inspecting `ChemicalSystem.bonds` for the carbon-carbon bond whose removal cuts the molecule.
- Central inter-ring bond, zero-based atom indices: `(5, 6)`
- Central inter-ring bond, AMS one-based atom indices: `(6, 7)`
- Inter-ring dihedral, zero-based atom indices: `(0, 5, 6, 7)`
- Inter-ring dihedral, AMS one-based atom indices: `(1, 6, 7, 8)`
The constrained AMS `PESScan` used DFTB with `Model GFN1-xTB`, scanning the inter-ring dihedral from 0 to 180 degrees in 19 points, i.e. 10 degree spacing. Energies below are reported relative to the lowest scan point.
## Results

Minimum-energy scan point: **140.0 degrees**.
Minimum-energy biphenyl twist angle: **40.0 degrees**. This is reported as `min(dihedral, 180 - dihedral)` because the 0 to 180 degree scan has equivalent twisted structures on either side of 90 degrees.
Torsional barrier to the planar structure: **1.8050 kcal/mol**. The 0 and 180 degree planar endpoints are both tabulated below; the quoted planar barrier is the lower of the two endpoint relative energies.
Torsional barrier to the perpendicular structure: **1.7045 kcal/mol**.
## Representative optimized structures
Planar geometry:

Minimum-energy geometry:

Perpendicular geometry:

## Scan table
| Dihedral angle (deg) | Absolute energy (Hartree) | Relative energy (kcal/mol) |
|:-----------------------|:----------------------------|:-----------------------------|
| 0.0 | -30.7270479157 | 1.8050 |
| 10.0 | -30.7276375568 | 1.4350 |
| 20.0 | -30.7287351168 | 0.7463 |
| 30.0 | -30.7296159661 | 0.1936 |
| 40.0 | -30.7299151698 | 0.0058 |
| 50.0 | -30.7296468314 | 0.1742 |
| 60.0 | -30.7289488005 | 0.6122 |
| 70.0 | -30.7281162675 | 1.1346 |
| 80.0 | -30.7274575254 | 1.5480 |
| 90.0 | -30.7272081545 | 1.7045 |
| 100.0 | -30.7274586820 | 1.5473 |
| 110.0 | -30.7281246087 | 1.1294 |
| 120.0 | -30.7289611334 | 0.6045 |
| 130.0 | -30.7296515698 | 0.1712 |
| 140.0 | -30.7299244088 | 0.0000 |
| 150.0 | -30.7296195325 | 0.1913 |
| 160.0 | -30.7287447482 | 0.7402 |
| 170.0 | -30.7276400215 | 1.4335 |
| 180.0 | -30.7270454035 | 1.8066 |
## AMS input
The PES scan job was loaded from `/home/ubuntu/work/01-run-biphenyl-dftb-pesscan_workdir/biphenyl_dftb_torsion` with `AMSJob.load_external(...)`.
```ams
PESScan
Optimize True
ScanCoordinate
Dihedral 1 6 7 8 0.0 180.0
nPoints 19
End
End
Task PESScan
System
Atoms
C 1.5436277587 -0.6712511736 -0.8743423895
C 2.9379238219 -0.6084386430 -0.7895740467
C 3.5458648903 0.1540229069 0.2101358580
C 2.7607157299 0.8559722841 1.1272880062
C 1.3659731986 0.7976348543 1.0467720204
C 0.7407365542 0.0321748032 0.0438974615
C -0.7407365262 -0.0321759898 -0.0438985615
C -1.3882544717 -1.2464975341 -0.3418076249
C -2.7829651518 -1.3041919267 -0.4233311075
C -3.5458647518 -0.1540214568 -0.2101369285
C -2.9156742946 1.0566598609 0.0856160895
C -1.5213463694 1.1201124254 0.1693765138
H 1.0941322198 -1.2547297485 -1.6679429353
H 3.5475041862 -1.1489839049 -1.5021581640
H 4.6253028921 0.2009111764 0.2741061689
H 3.2330362523 1.4435115455 1.9039896331
H 0.7773312479 1.3360188999 1.7788506547
H -0.8179456227 -2.1542017782 -0.4938473594
H -3.2727104357 -2.2427544850 -0.6487281126
H -4.6253028983 -0.2009093371 -0.2741044826
H -3.5078300382 1.9482274962 0.2468998516
H -1.0535181915 2.0729097247 0.3829394549
End
BondOrders
1 2 1.5
1 6 1.5
1 13 1.0
2 3 1.5
2 14 1.0
3 4 1.5
3 15 1.0
4 5 1.5
4 16 1.0
5 6 1.5
5 17 1.0
6 7 1.0
7 8 1.5
7 12 1.5
8 9 1.5
8 18 1.0
9 10 1.5
9 19 1.0
10 11 1.5
10 20 1.0
11 12 1.5
11 21 1.0
12 22 1.0
End
End
Engine dftb
Model GFN1-xTB
EndEngine
```
## Conclusion
The DFTB scan places the minimum at a scan dihedral of 140.0 degrees, corresponding to a biphenyl twist of 40.0 degrees. Relative to this point, the lower planar endpoint is 1.8050 kcal/mol higher and the perpendicular point is 1.7045 kcal/mol higher.